#include "ILImage.hpp"
#include <zImageAutoLink3rdParty.hpp>

#ifdef ZZZ_LIB_DEVIL
#include <cstring>
//
//
// ILIMAGE
//
//

ILImage::ILImage()
:Id(0)
{
  iStartUp();
  iGenBind();
  return;
}

ILImage::ILImage(const char *FileName)
:Id(0)
{
  iStartUp();
  iGenBind();
  ilLoadImage(FileName);
  return;
}

ILImage::ILImage(const ILImage &Image)
:Id(0)
{
  iStartUp();
  iGenBind();
  *this = Image;
  return;
}

ILImage::~ILImage()
{
  if (Id)
    ilDeleteImages(1, &Id);
  Id = 0;
  return;
}

ILboolean ILImage::Load(const char *FileName)
{
  iGenBind();
  return ilLoadImage(FileName);
}

ILboolean ILImage::Load(const char *FileName, ILenum Type)
{
  iGenBind();
  return ilLoad(Type, FileName);
}

ILboolean ILImage::Save(const char *FileName, bool overwrite)
{
  iGenBind();
  if (overwrite) ilEnable(IL_FILE_OVERWRITE);
  else ilDisable(IL_FILE_OVERWRITE);
  return ilSaveImage(FileName);
}

ILboolean ILImage::Save(const char *FileName, ILenum Type, bool overwrite)
{
  char filename[1024];
#ifdef WIN32
  strcpy_s(filename,1024,FileName);
#else
  strcpy(filename,FileName);
#endif
  iGenBind();
  if (overwrite) ilEnable(IL_FILE_OVERWRITE);
  else ilDisable(IL_FILE_OVERWRITE);
  return ilSave(Type, filename);
}

//
// ImageLib functions
//

ILboolean ILImage::ActiveImage(ILuint Number)
{
  if (Id) 
  {
    Bind();
    return ilActiveImage(Number);
  }
  return IL_FALSE;
}

ILboolean ILImage::ActiveLayer(ILuint Number)
{
  if (Id) 
  {
    Bind();
    return ilActiveLayer(Number);
  }
  return IL_FALSE;
}

ILboolean ILImage::ActiveMipmap(ILuint Number)
{
  if (Id) 
  {
    Bind();
    return ilActiveMipmap(Number);
  }
  return IL_FALSE;
}

ILboolean ILImage::Clear()
{
  if (Id) 
  {
    Bind();
    return ilClearImage();
  }
  return IL_FALSE;
}

void ILImage::ClearColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha)
{
  ilClearColour(Red, Green, Blue, Alpha);
  return;
}

ILboolean ILImage::Convert(ILenum NewFormat, ILenum NewType/*=IL_UNSIGNED_BYTE*/)
{
  if (Id) 
  {
    Bind();
    return ilConvertImage(NewFormat, NewType);
  }
  return IL_FALSE;
}

ILboolean ILImage::Copy(ILuint Src)
{
  if (Id) 
  {
    Bind();
    return ilCopyImage(Src);
  }
  return IL_FALSE;
}

ILboolean ILImage::Default()
{
  if (Id) 
  {
    Bind();
    return ilDefaultImage();
  }
  return IL_FALSE;
}

ILboolean ILImage::Flip()
{
  if (Id) 
  {
    Bind();
    return iluFlipImage();
  }
  return IL_FALSE;
}

ILboolean ILImage::SwapColours()
{
  if (Id) 
  {
    Bind();
    return iluSwapColours();
  }
  return IL_FALSE;
}

ILboolean ILImage::Resize(ILuint Width, ILuint Height, ILuint Depth)
{
  if (Id) 
  {
    Bind();
    return iluScale(Width, Height, Depth);
  }
  return IL_FALSE;
}

ILboolean ILImage::TexImage(ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data)
{
  if (Id) 
  {
    Bind();
    return ilTexImage(Width, Height, Depth, Bpp, Format, Type, Data);
  }
  return IL_FALSE;
}

//
// Image handling
//

void ILImage::Bind() const
{
  if (Id) ilBindImage(Id);
  return;
}

// Note:  Behaviour may be changed!
void ILImage::Bind(ILuint Image)
{
  if (Id == Image) return;
  Delete();  // Should we delete it?
  Id = Image;
  ilBindImage(Id);
  return;
}


void ILImage::Delete()
{
  if (Id == 0) return;
  ilDeleteImages(1, &Id);
  Id = 0;
  return;
}

//
// Image characteristics
//

ILuint ILImage::Width()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_WIDTH);
  }
  return 0;
}

ILuint ILImage::Height()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_HEIGHT);
  }
  return 0;
}

ILuint ILImage::Depth()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_DEPTH);
  }
  return 0;
}

ILubyte ILImage::Bpp()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
  }
  return 0;
}

ILubyte ILImage::Bitpp()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_BITS_PER_PIXEL);
  }
  return 0;
}

ILenum ILImage::Format()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_FORMAT);
  }
  return 0;
}

ILenum ILImage::PaletteType()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_PALETTE_TYPE);
  }
  return 0;
}

ILenum ILImage::PaletteAlphaIndex()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_PNG_ALPHA_INDEX);
  }
  return 0;
}


ILenum ILImage::Type()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_IMAGE_TYPE);
  }
  return 0;
}


ILenum ILImage::NumImages()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_NUM_IMAGES);
  }
  return 0;
}


ILenum ILImage::NumMipmaps()
{
  if (Id) 
  {
    Bind();
    return ilGetInteger(IL_NUM_MIPMAPS);
  }
  return 0;
}


ILuint ILImage::GetId() const
{
  return Id;
}

ILenum ILImage::GetOrigin(void)
{
    ILinfo Info;
  if (Id) 
  {
    Bind();
        iluGetImageInfo(&Info);
    return Info.Origin;
  }
  return 0;
}

ILubyte* ILImage::GetData()
{
  if (Id) 
  {
    Bind();
    return ilGetData();
  }
  return 0;
}

ILubyte* ILImage::GetPalette()
{
  if (Id) 
  {
    Bind();
    return ilGetPalette();
  }
  return 0;
}

//
// Private members
//

void ILImage::iStartUp()
{
  static bool ilinited=false;
  if (ilinited)
    return;
  ilInit();
  iluInit();
  ilutInit();
  ilEnable(IL_ORIGIN_SET);
  ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
  ilinited=true;
  return;
}

void ILImage::iGenBind()
{
  if (Id == 0) ilGenImages(1, &Id);
  ilBindImage(Id);
  return;
}

//
// Operators
//

ILImage& ILImage::operator = (ILuint Image)
{
  if (Id == 0) Id = Image;
  else 
  {
    Bind();
    ilCopyImage(Image);
  }
  return *this;
}


ILImage& ILImage::operator = (const ILImage &Image)
{
  if (Id == 0) Id = Image.GetId();
  else 
  {
    Bind();
    ilCopyImage(Image.GetId());
  }
  return *this;
}

//
//
// ILFILTERS
//
//

ILboolean ILFilters::Alienify(ILImage &Image)
{
  Image.Bind();
  return iluAlienify();
}

ILboolean ILFilters::BlurAvg(ILImage &Image, ILuint Iter)
{
  Image.Bind();
  return iluBlurAvg(Iter);
}

ILboolean ILFilters::BlurGaussian(ILImage &Image, ILuint Iter)
{
  Image.Bind();
  return iluBlurGaussian(Iter);
}

ILboolean ILFilters::Contrast(ILImage &Image, ILfloat Contrast)
{
  Image.Bind();
  return iluContrast(Contrast);
}

ILboolean ILFilters::EdgeDetectE(ILImage &Image)
{
  Image.Bind();
  return iluEdgeDetectP();
}

ILboolean ILFilters::EdgeDetectP(ILImage &Image)
{
  Image.Bind();
  return iluEdgeDetectP();
}

ILboolean ILFilters::EdgeDetectS(ILImage &Image)
{
  Image.Bind();
  return iluEdgeDetectS();
}

ILboolean ILFilters::Emboss(ILImage &Image)
{
  Image.Bind();
  return iluEmboss();
}

ILboolean ILFilters::Gamma(ILImage &Image, ILfloat Gamma)
{
  Image.Bind();
  return iluGammaCorrect(Gamma);
}

ILboolean ILFilters::Negative(ILImage &Image)
{
  Image.Bind();
  return iluNegative();
}

ILboolean ILFilters::Noisify(ILImage &Image, ILubyte Factor)
{
  Image.Bind();
  return iluNoisify(Factor);
}

ILboolean ILFilters::Pixelize(ILImage &Image, ILuint PixSize)
{
  Image.Bind();
  return iluPixelize(PixSize);
}

ILboolean ILFilters::Saturate(ILImage &Image, ILfloat Saturation)
{
  Image.Bind();
  return iluSaturate1f(Saturation);
}

ILboolean ILFilters::Saturate(ILImage &Image, ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation)
{
  Image.Bind();
  return iluSaturate4f(r, g, b, Saturation);
}

ILboolean ILFilters::ScaleColours(ILImage &Image, ILfloat r, ILfloat g, ILfloat b)
{
  Image.Bind();
  return iluScaleColours(r, g, b);
}

ILboolean ILFilters::Sharpen(ILImage &Image, ILfloat Factor, ILuint Iter)
{
  Image.Bind();
  return iluSharpen(Factor, Iter);
}

//
//
// ILOPENGL
//
//

//void ILOpenGL::Init()
//{
//  ilutRenderer(ILUT_OPENGL);
//  return;
//}
//
//GLuint ILOpenGL::BindTex(ILImage &Image)
//{
//  Image.Bind();
//  return ilutGLBindTexImage();
//}
//
//ILboolean ILOpenGL::Upload(ILImage &Image, ILuint Level)
//{
//  Image.Bind();
//  return ilutGLTexImage(Level);
//}
//
//GLuint ILOpenGL::Mipmap(ILImage &Image)
//{
//  Image.Bind();
//  return ilutGLBuildMipmaps();
//}
//
//ILboolean ILOpenGL::Screen()
//{
//  return ilutGLScreen();
//}
//
//ILboolean ILOpenGL::Screenie()
//{
//  return ilutGLScreenie();
//}
//
//void ILOpenGL::DrawImage(ILImage &image)
//{
//  glDrawPixels(image.Width(),image.Height(),image.Format(),image.Type(),image.GetData());
//}

//
//
// ILVALIDATE
//
//

ILboolean ILValidate::Valid(ILenum Type, char *FileName)
{
  return ilIsValid(Type, FileName);
}


ILboolean ILValidate::Valid(ILenum Type, FILE *File)
{
  return ilIsValidF(Type, File);
}


ILboolean ILValidate::Valid(ILenum Type, void *Lump, ILuint Size)
{
  return ilIsValidL(Type, Lump, Size);
}

//
//
// ILSTATE
//
//

ILboolean ILState::Disable(ILenum State)
{
  return ilDisable(State);
}

ILboolean ILState::Enable(ILenum State)
{
  return ilEnable(State);
}

void ILState::Get(ILenum Mode, ILboolean &Param)
{
  ilGetBooleanv(Mode, &Param);
  return;
}

void ILState::Get(ILenum Mode, ILint &Param)
{
  ilGetIntegerv(Mode, &Param);
  return;
}

ILboolean ILState::GetBool(ILenum Mode)
{
  return ilGetBoolean(Mode);
}

ILint ILState::GetInt(ILenum Mode)
{
  return ilGetInteger(Mode);
}

const char *ILState::GetString(ILenum StringName)
{
  return ilGetString(StringName);
}

ILboolean ILState::IsDisabled(ILenum Mode)
{
  return ilIsDisabled(Mode);
}

ILboolean ILState::IsEnabled(ILenum Mode)
{
  return ilIsEnabled(Mode);
}

ILboolean ILState::Origin(ILenum Mode)
{
  return ilOriginFunc(Mode);
}

void ILState::Pop()
{
  ilPopAttrib();
  return;
}

void ILState::Push(ILuint Bits = IL_ALL_ATTRIB_BITS)
{
  ilPushAttrib(Bits);
  return;
}

//
//
// ILERROR
//
//

void ILError::Check(void (*Callback)(const char *))
{
  static ILenum Error;
  while ((Error = ilGetError()) != IL_NO_ERROR) Callback(iluErrorString(Error));
  return;
}

void ILError::Check(void (*Callback)(ILenum))
{
  static ILenum Error;
  while ((Error = ilGetError()) != IL_NO_ERROR) Callback(Error);
  return;
}

ILenum ILError::Get()
{
  return ilGetError();
}

const char *ILError::String()
{
  return iluErrorString(ilGetError());
}

const char *ILError::String(ILenum Error)
{
  return iluErrorString(Error);
}
#endif // ZZZ_LIB_DEVIL
